package FIT::Document::Handler;

use FIT::Class;
use Memoize;
use aliased 'FIT::Util::ClassLoader';

has fixture_class => (is => 'ro', isa => 'Str', required => 1); 

my %Augmented_Fixtures;

sub add_handlers() { # augment a fixture with handlers
    my ($class, $fixture_class) = @_;
    return if $Augmented_Fixtures{ $fixture_class };

    $Augmented_Fixtures{ $fixture_class } = 1;
    my $self = $class->new(fixture_class => $fixture_class);
    $self->augment_fixture;
}

sub augment_fixture { $self->augment_hook($_) for qw(table row cell) }

sub augment_hook {
    my $hook      = shift;
    my $mechanism = $self;
    $self->fixture_class->meta->add_around_method_modifier(
        "do_$hook" => sub {
            my ($next, $fixture, $element) = @_;

            # we assume Attempt is 1st, Continue last
            my @handlers         = $mechanism->compute_handlers(ref($fixture), $hook);
            my $attempt_handler  = shift @handlers;
            my $continue_handler = $handlers[-1];

            $continue_handler->to($next);
            $attempt_handler->handle($fixture, $element, @handlers);
        }
    );
}

memoize('compute_handlers');

sub compute_handlers {
    my ($fixture_class, $hook) = @_;
    my $method = "${hook}_handlers";

    local $_;
    return map {

        my $handler_class = compute_handler_class($_);
        ClassLoader->load($handler_class);
        $handler_class->new;

    } ('Attempt', $fixture_class->$method, 'Continue');
}

sub compute_handler_class() { "FIT::Document::Handler::". shift }

